# 定制类


class Student(object):
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return 'Student object (name : %s)' % self.name

    __repr__ = __str__


s1 = Student('Json')
print(s1)
# 这是因为直接显示变量调用的不是__str__()，而是__repr__()，两者的区别是__str__()返回用户看到的字符串，
# 而__repr__()返回程序开发者看到的字符串，也就是说，__repr__()是为调试服务的。
# ----------------------------__iter__


class Fib(object):
    def __init__(self, num):
        self.a, self.b, self.num = 0, 1, num  # 初始化两个计数器a，b

# 要实现iteration需要写两个特定的方法

    def __iter__(self):
        return self  # 实例本身就是迭代对象，故返回自己

    def __next__(self):
        self.a, self.b = self.b, self.a + self.b  # 计算下一个值
        if self.a > self.num:  # 退出循环的条件
            raise StopIteration()
        return self.a  # 返回下一个值


for x in Fib(1000):
    print('打印循环对象:' + str(x))

# 像list那样按照下标取出元素，需要实现__getitem__()方法


class Find(object):
    def __getitem__(self, n):
        if isinstance(n, int):
            a, b = 1, 1
            for m in range(n):
                a, b, = b, a + b
            return a
        if isinstance(n, slice):
            start = n.start
            stop = n.stop
            if start is None:
                start = 0
            a, b = 1, 1
            ll = []
            for m in range(stop):
                if m >= start:
                    ll.append(a)
                a, b = b, a+b
            return ll


f2 = Find()
print(f2[0])
f3 = Find()
print(f3[:10])
# print(list(range(100))[5:10])


class Student(object):

    def __init__(self):
        self.name = 'Michael'

    def __getattr__(self, attr):  # 在使用对象获取属性时 Python解释器会试图调用__getattr__(self, 'XXX')来尝试获得属性
        if attr == 'score':
            return 88
        if attr == 'age':
            return lambda: 25
        raise AttributeError('\'Student\' object has no attribute \'%s\'' % attr)


print(Student().score)
print(Student().age())
# print(Student().salary)
# 链式调用


class Chain(object):

    def __init__(self, path=''):
        self._path = path

    def __getattr__(self, path):
        return Chain('%s/%s' % (self._path, path))

    def __str__(self):
        return self._path

    __repr__ = __str__


# __call__一个对象实例可以有自己的属性和方法，当我们调用实例方法时，我们用instance.method()来调用。
# 能不能直接在实例本身上调用呢？在Python中，答案是肯定的。
# 任何类，只需要定义一个__call__()方法，就可以直接对实例进行调用。请看示例：


class Animal(object):
    def __init__(self, name):
        self.name = name

    def __call__(self):
        return 'This animal is a %s' % self.name


a = Animal('Rabbit')
print(a())


# 通过callable()函数，我们就可以判断一个对象是否是“可调用”对象。

print(callable(Animal))
